home *** CD-ROM | disk | FTP | other *** search
- _THE DESIGN AND IMPLEMENTATION OF PIE MENUS_
- by Don Hopkins
-
- [LISTING ONE]
-
- % Code to implement the "8 Days a Week" Pie Menu
- % by Don Hopkins
-
- /pie framebuffer /new ClassPieMenu send def
- [ (Today)
- (Sunday)
- (Monday) (Tuesday) (Wednesday) (Thursday) (Friday)
- (Saturday)
- ] /setitemlist pie send
- 90 /setinitialangle pie send
- false /setclockwise pie send
-
- /can framebuffer /new ClassPieMenuCanvas send def
- pie /setpiemenu can send
- /minsize {100 100} /installmethod can send
- /win can framebuffer /new ClassBaseWindow send def
- /new ClassEventMgr send /activate win send
- /place win send /map win send
-
-
- [LISTING TWO]
-
- /Layout { % - => -
- PieGSave self setcanvas
- /LayoutInit self send
- /LayoutValidateItems self send
- /LayoutItemRadius self send
- /LayoutOuterRadius self send
- grestore
- } def
-
- /LayoutInit { % - => -
- % Deflate the menu.
- /Radius 0 def
- % Figure the slice width.
- /SliceWidth 360 /itemcount self send 1 max div def
- % Point the initial slice in the initial angle.
- /ThisAngle InitialAngle store
- } def
-
-
- /LayoutValidateItems { % - => -
- % Loop through the items, validating each one.
- ItemList {
- begin % item
-
- % Measure the item.
- /DisplayItem load DisplayItemSize
- /ItemHeight exch def
- /ItemWidth exch def
-
- % Remember the angle and the direction.
- /Angle ThisAngle def
- /DX Angle cos def
- /DY Angle sin def
-
- % Figure the offset from the tip of the inner radius
- % spoke to the lower left item corner, according to
- % the direction of the item.
- %
- % Items at the very top (bottom) are centered on their
- % bottom (top) edge. Items to the left (right) are
- % centered on their right (left) edge.
- %
- DX abs .05 lt { % tippy top or bippy bottom
-
- % Offset to the North or South edge of the item.
- /XOffset ItemWidth -.5 mul def
- /YOffset
- DY 0 lt {ItemHeight neg} {0} ifelse
- def
-
- } { % left or right
-
- % Offset to the East or West edge of the item.
- /XOffset
- DX 0 lt {ItemWidth neg} {0} ifelse
- def
- /YOffset ItemHeight -.5 mul def
-
- } ifelse
-
- % Twist around to the next item.
- /ThisAngle
- ThisAngle SliceWidth
- Clockwise? {sub} {add} ifelse
- NormalAngle
- store
-
- end % item
- } forall
- } def
-
- /LayoutItemRadius { % - => -
- % Figure the inner item radius, at least enough to prevent
-
- % the items from overlapping.
- /ItemRadius RadiusMin def
- /itemcount self send 3 gt { % No sweat if 3 or less.
-
- % Check each item against its next neighbor.
- 0 1 /itemcount self send 1 sub {
-
- /I exch def
- /NextI I 1 add /itemcount self send mod def
-
- % See if these two items overlap.
- % If they do, keep pushing the item radius out
- % by RadiusStep until they don't.
- { I /CalcRect self send
- NextI /CalcRect self send
- rectsoverlap not {exit} if % They don't overlap!
-
- % They overlap. Push them out a notch and try again.
- /ItemRadius ItemRadius RadiusStep add def
- } loop
-
- } for
- % Now that we've gone around once checking each pair,
- % none of them overlap any more!
- } if
-
- % Add in some more space to be nice.
- /ItemRadius ItemRadius RadiusExtra add def
- } def
-
- /LayoutOuterRadius { % - => -
- % Now we need to calculate the outer radius, based on the radius
- % of the farthest item corner. During the loop, Radius actually
- % holds the square of the radius, since we're comparing it against
- % squared item corner radii anyway.
- /Radius ItemRadius dup mul def
- ItemList {
- begin % item
-
- % Remember the location to center the item edge.
- /x DX ItemRadius mul def
- /y DY ItemRadius mul def
-
- % Remember the location of the item's SouthWest corner.
- /ItemX x XOffset add round def
- /ItemY y YOffset add round def
-
- % Figure the distance of the item's farthest corner.
- % This is easy 'cause we can fold all the items into
- % the NorthEast quadrant and get the same result.
- DX abs .05 lt { % tippy top or bippy bottom
-
- % (|x|,|y|) is South edge: radius^2 of NorthEast corner
- x abs ItemWidth .5 mul add dup mul
- y abs ItemHeight add dup mul add
-
-
- } { % left or right
-
- % (|x|,|y|) is West edge: radius^2 of NorthEast corner
- x abs ItemWidth add dup mul
- y abs ItemHeight .5 mul add dup mul add
-
- } ifelse
-
- % Remember the maximum corner radius seen so far.
- Radius max /Radius exch store
- end % item
- } forall
-
- % Take the square root and add some extra space.
- /Radius
- Radius sqrt Gap add Border add ceiling cvi
- store % Whew, we're done! Time to party!
- } def
-
-